package net.freebytes.ssmp.util;

import net.freebytes.ssmp.config.EnvironmentProperties;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

/**
 * 文件存储器
 *
 * @author 千里明月
 * @date 2021/7/20
 **/
public class FileStorer {


    private static final Logger logger = LoggerFactory.getLogger(FileStorer.class);

    /**
     * 上传者
     */
    private String applicant;
    /**
     * 上传根目录  绝对路径
     */
    private static String uploadPath = EnvironmentProperties.getUploadPath();
    /**
     * 源文件的根目录
     */
    private final static String SOURCE_ROOT = "/source";

    /**
     * 文件名
     */
    private String storeName;
    /**
     * 文件
     */
    private MultipartFile file;

    private File sourceDirectory = null;

    private static final String SLANTING_BAR = "/";


    /**
     * 输入相对路径得到文件对象
     *
     * @param path
     */
    public static File getAbsoluteFile(String path) {
        File canonicalFile = null;
        try {
            canonicalFile = new File(EnvironmentProperties.getUploadPath() + path).getCanonicalFile();
        } catch (IOException e) {
            logger.error("", e);
        }
        return canonicalFile;
    }

    /**
     * 得到标准化的文件路径
     *
     * @param url 输入路径
     * @return
     */
    public static String getCanonicalPath(String url) {
        if (!url.contains(EnvironmentProperties.getUploadPath())) {
            url = EnvironmentProperties.getUploadPath() + url;
        }
        url = url.replace("\\", "/")
                .replace("//", "/")
                .replace("//", "/");
        return url;
    }

    public void setUploadPath(String uploadPath) {
        uploadPath = uploadPath;
    }

    public FileStorer(String applicant, MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return;
        }
        this.applicant = StringUtils.isBlank(applicant) == true ? "anonymous" : applicant;
        this.sourceDirectory = initRootDirectory();
        this.storeName = this.applicant + "-" + UUID.randomUUID().toString().replaceAll("-", "") + "." + getSuffix(file.getOriginalFilename());
        this.storeName = this.storeName.toLowerCase();
        this.file = file;
    }

    private File initRootDirectory() {
        File file = new File(uploadPath + SOURCE_ROOT);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    /**
     * 得到文件后缀名
     *
     * @param fileName 文件名  或 文件路径
     * @return
     */
    public static String getSuffix(String fileName) {
        //文件分类识别
        return fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
    }

    /**
     * 从带有后缀名的文件名中 截取不带有后缀名的部分
     *
     * @param originName
     * @return
     */
    public static String getFileNameWithoutSuffix(String originName) {
        String name = getFileNameFromUrl(originName);
        return name.substring(0, name.lastIndexOf("."));
    }

    /**
     * 从文件路径中获取文件名
     *
     * @param url
     * @return
     */
    public static String getFileNameFromUrl(String url) {
        if (url.contains(SLANTING_BAR)) {
            url = url.substring(url.lastIndexOf(SLANTING_BAR) + 1, url.length());
        }
        return url;
    }

    /**
     * 从文件绝对路径中获取相对路径
     *
     * @param url
     * @return
     */
    public static String getRelativeUrl(String url) {
        url = url.replace("\\", "/")
                .replace("//", "/")
                .replace("//", "/");
        return url.substring(EnvironmentProperties.getUploadPath().length() - 1);
    }

    public String store(String category) {
        String originalFilename = file.getOriginalFilename();
        File directory = this.sourceDirectory;
        File parent = new File(directory, category);
        if (!parent.exists()) {
            parent.mkdirs();
        }
        File storer = new File(parent, storeName);
        if (storer.exists()) {
            logger.error(storeName + "文件已存在磁盘");
            return null;
        }
        try {
            store(this.file, storer);
        } catch (IOException e) {
            logger.error(originalFilename + "文件持久化出错", e);
            return null;
        }
        return SOURCE_ROOT + "/" + category + "/" + storeName;
    }


    /**
     * 文件存储
     *
     * @param file
     * @param newFile
     */
    private void store(MultipartFile file, File newFile) throws IOException {
//        file.transferTo(newFile);
        try (InputStream inputStream = file.getInputStream()) {
            FileUtils.copyInputStreamToFile(inputStream, newFile);
        }
    }

    public static void storeAnyWhere(MultipartFile file, File newFile) {
//        file.transferTo(newFile);
        try (InputStream inputStream = file.getInputStream();
        ) {
            FileUtils.copyInputStreamToFile(inputStream, newFile);
        } catch (IOException e) {
            logger.error("", e);
        }
    }

    /**
     * 删除源文件
     *
     * @param urls
     */
    public static void delete(String... urls) {
        try {
            for (String url : urls) {
                if (StringUtils.isBlank(url)) {
                    continue;
                }
                File file = new File(uploadPath, url);
                if (file.exists()) {
                    try {
                        file.delete();
                    } catch (Exception e) {
                        logger.error("删除文件出错--" + url);
                    }
                }
            }
        } catch (Exception e) {
            logger.error("删除文件出错--", e);
        }
    }

    /**
     * 递归删除文件
     *
     * @param source
     */
    public static void deleteFileOnDeep(File source) {
        if (!source.isDirectory()) {
            source.delete();
            return;
        }
        for (File file : source.listFiles()) {
            deleteFileOnDeep(file);
        }
        source.delete();
    }

    /**
     * 递归创建文件夹
     *
     * @param source
     * @param names
     */
    public static String mkdirs(String source, List<String> names) {
        File file = new File(source);
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
        for (String name : names) {
            File f = new File(file, name);
            f.mkdirs();
            file = f;
        }
        return file.getPath();
    }

    /**
     * 创建文件夹
     *
     * @param file
     */
    public static File mkdirs(File file) {
        if (!file.exists() || !file.isDirectory()) {
            file.mkdirs();
        }
        return file;
    }


    /**
     * 创建文件, 如果存在相同文件 则覆盖
     *
     * @param path
     */
    public static File create(String path) {
        File file = new File(path);
        try {
            if (file != null) {
                if (file.exists() && file.isFile()) {
                    file.delete();
                }
                file.createNewFile();
            }
        } catch (IOException e) {
            logger.error("", e);
        }
        return file;
    }


    /**
     * 文件回滚器
     */
    interface RollBacker {
        /**
         * 记录备份点
         *
         * @param path 文件地址(目录或者文件)
         */
        void record(String path);

        /**
         * 回滚
         */
        void rollback();
    }

    class RollBack implements RollBacker {

        private String path;

        @Override
        public void record(String path) {
            this.path = path;
        }

        @Override
        public void rollback() {

        }
    }

}
